﻿//TODO: test, Texture

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    ///
    /// </summary>
    public class Texture : BaseImageFilter
    {
        protected float m_fTextureTransparency = 0.5f;
        protected Image m_TextureImage = new Bitmap(100,100);
        protected GrayScale m_Grayscale = new GrayScale();

        /// <summary>
        /// Default constructor
        /// </summary>
        public Texture()
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_texture"></param>
        /// <param name="_textureTransparency"></param>
        public Texture(Image _texture, float _textureTransparency)
        {
            m_fTextureTransparency = _textureTransparency;
        }

        /// <summary>
        /// Use this to create a copy of this filter
        /// </summary>
        /// <param name="_texture"></param>
        internal Texture(Texture _texture)
        {
        }

        /// <summary>
        /// Gets or sets the texture transparency
        /// </summary>
        public float TextureTransparency
        {
            get { return m_fTextureTransparency; }
            set { m_fTextureTransparency = value; }
        }

        /// <summary>
        /// Gets or sets the texture image.
        /// </summary>
        /// <value>The texture image.</value>
        public Image TextureImage
        {
            get { return m_TextureImage; }
            set { m_TextureImage = value; }
        }

        /// <summary>
        /// Your project needs to be able to execute unsafe code:
        /// Right click on your project, go to Properties, click on Configuration Properties
        /// in the Build section, make "Allow unsafe code blocks" to true
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        /// <remarks>Make sure the texture isnt of an indexed image format.</remarks>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            Image image = _bitmap.InternalBitmap;
            unsafe
            {
                if ((image == null) || (m_TextureImage == null))
                {
                    throw new ArgumentNullException();
                }
                if (m_fTextureTransparency < 0 || m_fTextureTransparency > 1)
                {
                    throw new ArgumentOutOfRangeException(
                        "Value must be between 0 and 1.");
                }

                // Convert the texture to grayscale before using it
                m_Grayscale.Execute(m_TextureImage).Dispose();

                Bitmap bitmapTexture = (Bitmap)m_TextureImage;

                int nTextureHeight = bitmapTexture.Height;
                int nTextureWidth = bitmapTexture.Width;

                BitmapData bitmapData = bitmapTexture.LockBits(new Rectangle(0, 0,
                    bitmapTexture.Width, bitmapTexture.Height),
                    ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                int stride = bitmapData.Stride;
                IntPtr Scan0 = bitmapData.Scan0;
                
                // Adjust the alpha value of each pixel in the texture bitmap.
                // The white-most pixels will have the the
                // most transparency (highest alpha),
                // and the dark-most pixels will have the least transparency.


                byte* p = (byte*)(void*)Scan0;
                int nOffset = stride - nTextureWidth * 4;


                for (int y = 0; y < nTextureHeight; ++y)
                {
                    for (int x = 0; x < nTextureWidth; ++x)
                    {
                        // p[3] is alpha  -  array is BGRA (blue, green ,
                        // red, alpha)
                        p[3] = (byte)(*p * m_fTextureTransparency);
                        p += 4; // Move to the next pixel
                    }
                    p += nOffset;
                }
                bitmapTexture.UnlockBits(bitmapData);

                Graphics gr = Graphics.FromImage(image);
                TextureBrush myBrush = new TextureBrush(bitmapTexture);
                gr.FillRectangle(myBrush, 0, 0, image.Width, image.Height);
                myBrush.Dispose();
                gr.Dispose();
                bitmapTexture.Dispose();
                return _bitmap;
            }
        }

        /// <summary>
        /// Clone this filter
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Texture(this.m_TextureImage, this.m_fTextureTransparency);
        }
    }
}
